package com.easpeed.elevator.otdr;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.bigyu.utils.Logger;
import com.blankj.utilcode.util.ToastUtils;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

public class OtdrController {
    private String TAG = "OtdrController";
    private static final int MAX_RETRIES = 500;
    private static final int TIMEOUT = 150;

    // 折射率
    private static final float REFRACTION = 1.467f;
    public OTDRDataProcessor processor = new OTDRDataProcessor();


    public int orderXh = 1;
    // 命令字常量
    public String mlzcl = "";
    // 监听获取到的命令数据
    public String mlsj = "";
    // 打算发给TCP用户端的OTDR数据
    public String mlsjBox = "";
    // OTDR测试结果点数
    public int csds = 0;
    // OTDR串口下发的数据容器
    public String otdrData = "";

    public float pointDistance = 0f;
    public int maxDistance = 0;

    private AtomicInteger receiveFlag = new AtomicInteger(0);  // 0:数据未返回，不需要重发 1：返回成功 2：返回失败，需重发
    private int mlz = 0; // Command word
    private int setp = 3; // State variable
    private int eventCount = 0;

    public boolean isTest = false;

    private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    private ISerSender iss;
    // OTDR 设置实例
    public OTDRSet otdrSet = new OTDRSet(50000, 100, 5, REFRACTION);

    public void setOtdrSet(int sampleRange, int pulseWidth, int duration, float refraction) {
        otdrSet = new OTDRSet(sampleRange, pulseWidth, duration, refraction);
    }

    public void setOtdrSetWithBc(int sampleRange, int pulseWidth, int duration, float refraction, String bc) {
        otdrSet = new OTDRSet(sampleRange, pulseWidth, duration, refraction, bc);
    }

    public void sendOtdr(String data, int mlz, int xhcs) {
        sendOtdr1(data, mlz, xhcs, TIMEOUT);
    }

    public void sendOtdrStart(String data, int mlz, int xhcs, float zsl, String bc) {
//        加这一行
//        setOtdrSetWithBc(50000, 100, 5, zsl , bc);
        sendOtdr1(data, mlz, xhcs, TIMEOUT);
    }

    public void setMaxDistance(int _maxDistance) {
        maxDistance = _maxDistance;
    }

    public void receive(String _hexStr) {
        otdrData += _hexStr;
        sjjt();
    }

    public void setSender(ISerSender ss) {
        iss = ss;
        // Implement the actual sending of the command here

    }

    // Placeholder for methods like sendHexStr, processHex, decToHex2byte, decToHex1byte, hexzhuan10, float32ToHex, etc.
    private void sendHexStr(String order) {
        // Implement the actual sending of the command here
        iss.SendSerStr(order);
    }


    private void sendOtdr1(String data, int mlz, int xhcs, int timeOut) {
        scheduler.schedule(() -> {
            Logger.d(TAG, "Sending OTDR command with data: " + data + ", mlz: " + mlz + ", xhcs: " + xhcs);
            if (xhcs > MAX_RETRIES) {
                Logger.w(TAG, "Exceeded maximum retries for command.");
                return;
            }

            int sjcd = (data.isEmpty()) ? 0 : data.length() / 2; // Data length
            int mlzcd = 8 + sjcd; // Command frame length
            String mlzcdZh = decToHex2byte(mlzcd);
            String ztjyZh = processHex("aa" + mlzcdZh); // Frame header checksum conversion

            String zxbhzh = "ffff"; // Bus number
            String mlxhzh = decToHex2byte(orderXh); // Command sequence number conversion
            String mlzzh = decToHex1byte(mlz); // Command word
            String kzzzh = "1c"; // Control word
            String sjcdzh = decToHex2byte(sjcd); // Data length conversion
            String mlzjyzh = processHex(zxbhzh + mlxhzh + mlzzh + kzzzh + sjcdzh + data); // Command frame checksum conversion
            String order = "aa" + mlzcdZh + ztjyZh + zxbhzh + mlxhzh + mlzzh + kzzzh + sjcdzh + data + mlzjyzh;

            Logger.d(TAG, "mlzcdZh: " + mlzcdZh);
            Logger.d(TAG, "ztjyZh: " + ztjyZh);
            Logger.d(TAG, "zxbhzh: " + zxbhzh);
            Logger.d(TAG, "mlxhzh: " + mlxhzh);
            Logger.d(TAG, "mlzzh: " + mlzzh);
            Logger.d(TAG, "kzzzh: " + kzzzh);
            Logger.d(TAG, "sjcdzh: " + sjcdzh);
            Logger.d(TAG, "data: " + data);
            Logger.d(TAG, "mlzjyzh: " + mlzjyzh);

            Logger.d(TAG, "Command order: " + order);
            sendHexStr(order); // Send the command frame

            mlzcl = mlzzh;
            receiveFlag.set(0);
            orderXh++;

            for (int i = xhcs; i < MAX_RETRIES; i++) {
                if (receiveFlag.get() == 0) {
//                    Logger.w(TAG, "sleep :"+mlz);
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        Logger.e(TAG, "Sleep interrupted: " + e.getMessage());
                    }
                } else {
                    Logger.w(TAG, "sleep over:" + receiveFlag.get());
                    break;
                }
            }
            Logger.w(TAG, "sleep for end:" + receiveFlag.get());
            if (receiveFlag.get() == 2) {
                Logger.w(TAG, "Retrying sendOtdr due to timeout.");
                sendOtdr(data, mlz, xhcs + 1); // Retry on failure
            }
        }, timeOut, TimeUnit.MILLISECONDS);
    }

    public void sjjt() {
        String hexStr = otdrData.toString().toLowerCase();
        Logger.d(TAG, "Received data: " + hexStr);

        if (hexStr.length() < 26) {
            Logger.w(TAG, "Data length is less than required.");
            return;
        }

        String zt = hexStr.substring(0, 2);
        if (!zt.equals("aa")) {
            Logger.e(TAG, "Invalid frame header.");
            receiveFlag.set(2);
            otdrData = "";
            return;
        }

        String mlzcd = hexStr.substring(2, 6);
        String ztjy = hexStr.substring(6, 8);
        String ztjyzh = processHex("aa" + mlzcd);

        String mlz = hexStr.substring(16, 18);
        String kzz = hexStr.substring(18, 20);
        String zxbhzh = hexStr.substring(8, 12); // Bus number
        String mlxhzh = hexStr.substring(12, 16); // Command sequence number

        if (!mlz.equals("06")) {
            if (!ztjy.equals(ztjyzh)) {
                Logger.d(TAG, "Params: mlz=" + mlz + ", ztjy=" + ztjy + ", ztjyzh=" + ztjyzh);
                receiveFlag.set(2);
                otdrData = "";
                return;
            }
        }

        if (!mlzcl.equals(mlz) || !kzz.equals("a1")) {
            Logger.d(TAG, "Params: mlzcl=" + mlzcl + ", mlz=" + mlz + ", kzz=" + kzz);
            receiveFlag.set(2);
            otdrData = "";
            return;
        }

        String sjcd = hexStr.substring(20, 24); // Get data length
        int sjcdNum = hexzhuan10(sjcd) * 2; // Convert to decimal
        if (hexStr.length() < 26 + sjcdNum) {
            return;
        }
        String data = hexStr.substring(24, 24 + sjcdNum);
        String mlzjyzh = processHex(zxbhzh + mlxhzh + mlz + kzz + sjcd + data); // Command frame checksum conversion
        String mlzjy = hexStr.substring(24 + sjcdNum, 24 + sjcdNum + 2); // Parsed command frame checksum

        if (!mlzjy.toLowerCase().equals(mlzjyzh.toLowerCase())) {
            Logger.d(TAG, "Params: mlzjy=" + mlzjy + ", mlzjyzh=" + mlzjyzh);
            otdrData = ""; // Clear data on error
            receiveFlag.set(2);
            return;
        } else {
            otdrData = otdrData.substring(26 + sjcdNum);
            ; // Clear processed data
        }

        // 处理不同的命令响应
        switch (mlz) {
            case "01":
                Logger.d(TAG, "Processing command 01.");
                String data03 = String.format("0100000000%s%s00000000%s%s000000000000%s",
                        decToHex1byte(otdrSet.duration),
                        otdrSet.bc,
                        decToHex4byte(otdrSet.sampleRange),
                        decToHex2byte(otdrSet.pulseWidth),
                        float32ToHex(otdrSet.refraction));
//                String data03 = String.format("0100000000%s1e0500000000%s0000%s000000000000%s",
//                        decToHex1byte(otdrSet.duration),
//                        decToHex2byte(otdrSet.sampleRange),
//                        decToHex2byte(otdrSet.pulseWidth),
//                        float32ToHex(otdrSet.refraction));
                sendOtdr(data03, 4, 0); // Start test command
                Logger.d("OTDRSetData", String.format("Duration: %s, Sample Range: %s, Pulse Width: %s, Refraction: %s",
                        otdrSet.duration,
                        otdrSet.sampleRange,
                        otdrSet.pulseWidth,
                        otdrSet.refraction));
                Logger.d("OTDRSetData", "data03: " + data03);
                break;

            case "04":

                Logger.d(TAG, "Processing command 04");
                scheduler.schedule(() -> {
                    sendOtdr("", 3, 0); // Query test status command
                    setp = 3;
                }, 2000, TimeUnit.MILLISECONDS);
                break;

            case "03":
                Logger.d(TAG, "Processing command 03.");
                if (setp == 3) {
                    String cssj = data.substring(10, 12);
                    String jlsj = data.substring(12, 14);
                    Logger.d(TAG, "cssj: " + cssj + ", jlsj: " + jlsj);

                    if (cssj.equals("00")) {
                        Logger.d(TAG, "cssj is 00, scheduling sendOtdr with delay.");
                        scheduler.schedule(() -> {
                            sendOtdr("", 3, 0);
                        }, 200, TimeUnit.MILLISECONDS);
                    } else {
                        if (!cssj.equals(jlsj)) {
                            Logger.d(TAG, "cssj does not equal jlsj, setting receiveFlag to 2.");
                            receiveFlag.set(2);
                            return;
                        } else {
                            Logger.d(TAG, "Sending query test status command.");
                            sendOtdr("", 12, 0); // Query test status command
                        }
                    }
                } else if (setp == 6) {
                    String sjbzw = data.substring(18, 20);
                    Logger.d(TAG, "sjbzw: " + sjbzw);

                    if (sjbzw.equals("00")) {
                        Logger.d(TAG, "sjbzw is not 00, setting receiveFlag to 1.");
                        receiveFlag.set(1);
//                        sendOtdr("", 3, 0);
                    } else {
                        Logger.d(TAG, "Sending read event analysis status command.");
                        sendOtdr("", 8, 0); // Read event analysis status command step 7
                    }
                }
                break;

            case "0c":
                Logger.d(TAG, "Processing command 0C, getting test points count.");

                Map<String, Object> dm = getOtdrPoint(hexStr);
                pointDistance = (float) dm.get("点间距");
                csds = hexzhuan10(hexStr.substring(40, 44)); // Test points count (converted to decimal)

                Logger.d(TAG, "Processing command 0C, getting test points distance." + pointDistance);
                int start = 0;
                int xhfscs = (int) Math.ceil(csds / 512.0);
                Logger.d(TAG, "delayed loop:" + start + ";" + xhfscs);
                delayedLoop(start, xhfscs, 250);
                break;

            case "06":
                Logger.d(TAG, "Processing command 06.");
                mlsj = mlsj + (hexStr.substring(48, hexStr.length() - 2));
                if (mlsj.length() >= (Math.ceil(csds / 512.0) * 2048)) {
                    mlsjBox = mlsj;
                    iss.responseToUser(mlsj, pointDistance, maxDistance);
                    iss.OnOTDRData(processor.dataProcessing(csds, otdrSet, mlsj, pointDistance, maxDistance));
                    isTest = false;
                    mlsj = ""; // Reset after processing
                    setp = 6;
                    sendOtdr("", 3, 0); // Query test status command
                }
                break;

            case "08":
                eventCount = getEventCount(hexStr);
//                sendOtdr("010000000200000000000000", 9, 0); // Query test status command step 8
//                new Handler(Looper.getMainLooper()) .post(new Runnable() {
//                    @Override
//                    public void run() {
//                        ToastUtils.showShort("OTDR测试读取事件个数，事件个数"+eventCount);
//                        ToastUtils.showShort("OTDR测试读取事件个数，事件个数"+String.format("01000000%s00000000", decToHex4byte(eventCount)));
//                    }
//                });
                sendOtdr(String.format("01000000%s00000000", decToHex4byte(eventCount)), 9, 0); // Query test status command step 8
                Logger.d(TAG, "Processing command 08, sending status query:" + eventCount);
                receiveFlag.set(1);
                break;

            case "09":
                Logger.d(TAG, "Processing command 09.");
                List<Map<String, Object>> eventList = parseOtdrData(hexStr, eventCount);
                iss.OnEventList(eventList);
                receiveFlag.set(1);
                break;
        }
        receiveFlag.set(1);
    }

    /**
     * OTDR的测试参数解析 这里需使用到测试结果点数以及点间距，这两个参数
     *
     * @param hexString
     * @return java.util.Map<java.lang.String, java.lang.Object>
     * @Date 2024-10-22 14:12
     * @author 朱兴邦
     **/
    public static Map<String, Object> getOtdrPoint(String hexString) {
        // 将16进制字符串转换为字节数组
        byte[] byteArray = hexStringToByteArray(hexString);

        // 使用 ByteBuffer 解析数据
        ByteBuffer buffer = ByteBuffer.wrap(byteArray);
        buffer.order(ByteOrder.LITTLE_ENDIAN);
        // 前面12字节为发送命令，这里不需要
        buffer.position(12); // 跳过前12字节
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("测量序号", buffer.getInt());
        dataMap.put("测试模式", buffer.get());
        dataMap.put("测试时间", buffer.get());
        dataMap.put("波长", buffer.getShort());
        dataMap.put("点数", buffer.getInt());
        dataMap.put("量程", buffer.getInt());
        dataMap.put("脉冲宽度", buffer.getShort());
        dataMap.put("保留1", buffer.get());
        dataMap.put("保留2", buffer.get());
        dataMap.put("点间距", buffer.getFloat());
        dataMap.put("折射率", buffer.getFloat());
        Logger.d("Sheng4", "Data :" + dataMap.toString() + ",hex:" + hexString);
        return dataMap;
    }

    private final static String sjxh = "sjxh";// 事件序号  （N）uint32
    private final static String sjlx = "sjlx";// 事件类型       uint32
    private final static String qswz = "qswz";// 起始位置（N）    int32
    private final static String qsjl = "qsjl";// 起始距离（KM）   float
    private final static String qsgl = "qsgl";// 起始功率（dB）   float
    private final static String fzwz = "fzwz";// 峰值位置（N）    int32
    private final static String fzjl = "fzjl";// 峰值距离（KM）   float
    private final static String fzgl = "fzgl";// 峰值功率（dB）   float
    private final static String jswz = "jswz";// 结束位置（N）    int32
    private final static String jsjl = "jsjl";// 结束距离（KM）   float
    private final static String jsgl = "jsgl";// 结束功率（dB）   float
    private final static String crsh = "crsh";// 插入损耗（dB）   float
    private final static String hbsh = "hbsh";// 回波损耗（KM）   float
    private final static String fdsh = "fdsh";// 分段衰耗（dB）   float
    private final static String fdcd = "fdcd";// 分段长度（KM）   float
    private final static String fdjh = "fdjh";// 分段均耗（dB/KM）    float
    private final static String blzd = "blzd";// 保留字段      uint32


    public static List<Map<String, Object>> parseOtdrData(String hexString, int num) {
        Logger.d("Sheng", "Data Item " +hexString.toString());

        List<Map<String, Object>> list = new ArrayList<>();
        // 将16进制字符串转换为字节数组
        byte[] byteArray = hexStringToByteArray(hexString);

        // 使用 ByteBuffer 解析数据
        ByteBuffer buffer = ByteBuffer.wrap(byteArray);
        buffer.order(ByteOrder.LITTLE_ENDIAN);
        // 前面12字节为发送命令，这里不需要
        buffer.position(24); // 跳过前24字节

        for (int i = 0; i < num; i++) {
            if (buffer.remaining() < 68) break;
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("事件序号", (long) (buffer.getInt()));
            dataMap.put("事件类型", buffer.getInt());
            dataMap.put("起始位置", buffer.getInt());
            dataMap.put("起始距离", buffer.getFloat());
            dataMap.put("起始功率", buffer.getFloat());
            dataMap.put("峰值位置", buffer.getInt());
            dataMap.put("峰值距离", buffer.getFloat());
            dataMap.put("峰值功率", buffer.getFloat());
            dataMap.put("结束位置", buffer.getInt());
            dataMap.put("结束距离", buffer.getFloat());
            dataMap.put("结束功率", buffer.getFloat());
            dataMap.put("插入损耗", buffer.getFloat());
            dataMap.put("回波损耗", buffer.getFloat());
            dataMap.put("分段衰耗", buffer.getFloat());
            dataMap.put("分段长度", buffer.getFloat());
            dataMap.put("分段均耗", buffer.getFloat());
            dataMap.put("保留字段", (long) (buffer.getInt()));
            list.add(dataMap);
            Logger.d("Sheng", "Data Item " + i + ": " + dataMap.toString());
        }
        return list;
    }

    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i + 1), 16));
        }
        return data;
    }

    public static int getEventCount(String hexString) {
        // 将16进制字符串转换为字节数组
        byte[] byteArray = hexStringToByteArray(hexString);

        // 使用 ByteBuffer 解析数据
        ByteBuffer buffer = ByteBuffer.wrap(byteArray);
        buffer.order(ByteOrder.LITTLE_ENDIAN); // 设置字节顺序为小端

        return buffer.getInt(byteArray.length - 9);
    }


    private void delayedLoop(int start, int xhfscs, int delay) {
        if (start >= xhfscs) {
            return; // Exit recursion
        }
        sendOtdr1(String.format("0100000001010004%s", decToHex4byte(start * 1024)), 6, 0, 0);
        scheduler.schedule(() -> {
            delayedLoop(start + 1, xhfscs, delay);
        }, delay, TimeUnit.MILLISECONDS);
    }

    public static String decToHex2byte(int dec) {
        // 将十进制数转换为十六进制字符串
        String hex = Integer.toHexString(dec);

        // 如果转换后的十六进制字符串长度是奇数，前面补一个'0'以保持偶数长度
        if (hex.length() % 2 != 0) {
            hex = "0" + hex;
        }

        // 如果长度小于4，前补0
        while (hex.length() < 4) {
            hex = "0" + hex;
        }

        // 将前两个字符与后两个字符换位（小端格式）
        return (hex.substring(2) + hex.substring(0, 2)).toLowerCase();
    }



    public static String decToHex1byte(int dec) {
        // Convert the decimal number to a hexadecimal string
        String hex = Integer.toHexString(dec);

        // If the length of the hex string is odd, prepend '0' to make it even
        if (hex.length() % 2 != 0) {
            hex = "0" + hex;
        }

        // Return the hex string in lowercase
        return hex.toLowerCase();
    }

    public static int hexzhuan10(String hexString) {
        // 确保输入是有效的16进制字符串
        if (!hexString.matches("^[0-9a-fA-F]+$")) {
            throw new IllegalArgumentException("Invalid hex string");
        }

        // 将16进制字符串转换为字节数组
        byte[] bytes = new byte[hexString.length() / 2];
        for (int i = 0; i < hexString.length(); i += 2) {
            bytes[i / 2] = (byte) Integer.parseInt(hexString.substring(i, i + 2), 16);
        }

        // 根据字节序调整字节数组
        reverseArray(bytes);

        // 将字节数组转换为10进制数
        int decimal = 0;
        for (byte b : bytes) {
            decimal = decimal * 256 + (b & 0xFF); // 处理无符号字节
        }

        return decimal;
    }

    // 反转字节数组的辅助方法
    private static void reverseArray(byte[] array) {
        int left = 0, right = array.length - 1;
        while (left < right) {
            byte temp = array[left];
            array[left] = array[right];
            array[right] = temp;
            left++;
            right--;
        }
    }

    // 十进制数转换为十六进制字符串且为4byte小端方法
    public static String decToHex4byte(int dec) {
        // 确保输入是32位无符号整数
        ByteBuffer buffer = ByteBuffer.allocate(4);
        buffer.order(ByteOrder.LITTLE_ENDIAN); // 设置为小端模式
        buffer.putInt(dec);

        StringBuilder hex = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            int byteValue = buffer.get(i) & 0xFF; // 获取每个字节
            hex.append(String.format("%02x", byteValue)); // 转换为十六进制
        }
        return hex.toString();
    }

    // 计算校验和
    public static String processHex(String hex) {
        // 确保输入是有效的16进制字符串
        if (!hex.matches("[0-9a-fA-F]+")) {
            throw new IllegalArgumentException("Invalid hex string");
        }

        int sum = 0;
        for (int i = 0; i < hex.length(); i += 2) {
            String byteHex = hex.substring(i, Math.min(i + 2, hex.length()));
            sum += Integer.parseInt(byteHex, 16); // 将每个16进制数转换为十进制并累加
        }

        // 对总和进行取反加1
        int invertedSum = (~sum + 1) & 0xFF;
        // 将结果转换为16进制字符串
        return String.format("%02x", invertedSum).toLowerCase();
    }

    // 单精度浮点转换为16进制（小端字节）
    public static String float32ToHex(float value) {
        ByteBuffer buffer = ByteBuffer.allocate(4);
        buffer.order(ByteOrder.LITTLE_ENDIAN); // 设置为小端模式
        buffer.putFloat(value);

        StringBuilder hex = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            int byteValue = buffer.get(i) & 0xFF; // 获取每个字节
            hex.append(String.format("%02x", byteValue)); // 转换为十六进制
        }
        return hex.toString();
    }

    // 16进制（小端字节）转换为单精度浮点
    public static float hexToFloat32(String hex) {
        if (hex.length() != 8) {
            throw new IllegalArgumentException("Hex string must be 8 characters long for single precision");
        }

        ByteBuffer buffer = ByteBuffer.allocate(4);
        buffer.order(ByteOrder.LITTLE_ENDIAN); // 设置为小端模式

        for (int i = 0; i < 4; i++) {
            int byteValue = Integer.parseInt(hex.substring(i * 2, i * 2 + 2), 16);
            buffer.put(i, (byte) byteValue); // 将字节写入ArrayBuffer
        }

        return buffer.getFloat(0); // 从ArrayBuffer中读取单精度浮点数
    }

}
